﻿using System;

using iStudio.Structure.Wave;

using WaveFormat = NAudio.Wave.WaveFormat;

namespace iStudio.Engine
{
    /// <summary>
    /// NAudio track wrapper for channel mixer
    /// </summary>
    internal class NAudioTrack : INAudioStream
    {
        private readonly NAudioMixer _autoMixer;
        private readonly NAudioChannel _autoChannel;
        private readonly WaveTrack _track;

        public NAudioTrack (WaveChannel channel, WaveTrack track)
        {
            if (channel == WaveChannel.SPEAKER_AUTO)
            {
                throw new ArgumentException("Track wrapper cannot output Auto panned audio.");
            }

            _track = track;

            //
            // Track is always a single channel, either single channel from track or complete track together
            //

            //WaveFormat = NAudio.Wave.WaveFormat.CreateIeeeFloatWaveFormat(44100, 1);

            //
            // If track is set to automatic, only channel samples will be read
            //

            if (track.OutputChannel != WaveChannel.SPEAKER_AUTO)
            {
                _autoMixer = new NAudioMixer();

                //
                // Put all channels into mixer
                //

                for (int i = 0; i < track.WaveFormat.Channels; i++)
                {
                    _autoMixer.AddMixerInput(new NAudioChannel((WaveChannel) i, track));
                }
            }
            else
            {
                _autoChannel = new NAudioChannel(channel, track);
            }
        }

        public long Length
        {
            get
            {
                if (_track.OutputChannel == WaveChannel.SPEAKER_AUTO)
                {
                    return _autoChannel.Length;
                }

                return _autoMixer.Length;
            }
        }

        public long Position
        {
            get
            {
                if (_track.OutputChannel == WaveChannel.SPEAKER_AUTO)
                {
                    return _autoChannel.Position;
                }

                return _autoMixer.Position;
            }
            set
            {
                if (_track.OutputChannel == WaveChannel.SPEAKER_AUTO)
                {
                    if ( (_autoChannel != null) && (_autoChannel.Position != value) )
                    {
                        _autoChannel.Position = value;
                    }
                }
                else
                {
                    if ( (_autoMixer != null) && (_autoMixer.Position != value) )
                    {
                        _autoMixer.Position = value;
                    }
                }
            }
        }

        public WaveFormat WaveFormat
        {
            get
            {
                return WaveFormat.CreateIeeeFloatWaveFormat(44100, 1);
            }
        }

        public int Read(float[] buffer, int offset, int count)
        {
            //
            // If it is auto, output single channel from track, otherwise output mix
            //

            int readSamples = (_track.OutputChannel == WaveChannel.SPEAKER_AUTO) ? _autoChannel.Read (buffer, offset, count) : _autoMixer.Read(buffer, offset, count);

            _track.Output.Process(buffer, offset, readSamples);

            return readSamples;
        }
    }
}
